﻿#include "MyGrayImage.h"

//Định nghĩa giá trị cutoff
#define cutoff 0.03

MyGrayImage::MyGrayImage(void)
{
}

MyGrayImage::~MyGrayImage(void)
{
}

//Khởi tạo ảnh từ 1 ảnh màu và chuyển về ảnh xám
MyGrayImage::MyGrayImage(IplImage*img){
	//Gọi hàm tạo ảnh xám	
	if(img->nChannels==3)
		RGB2Gray(img);
	else
		this->grayImg=img;
}

// Author: 1041399-Minh Phượng
// Function: Hàm chuyển từ ảnh màu sang ảnh xám
void MyGrayImage::RGB2Gray(IplImage *img){

	//Tạo 1 ảnh xám rỗng
	this->grayImg=cvCreateImage(cvGetSize(img),IPL_DEPTH_8U,1);

	int imgHeight=img->height;
	int imgWidthStep=img->widthStep;
	int step=img->widthStep;
	int grayStep=this->grayImg->widthStep;

	uchar*data=(uchar*)img->imageData;
	uchar*grayData=(uchar*)this->grayImg->imageData;
	
	//Gán giá trị cho ảnh xám tạo bên trên
	for(int j=0;j<imgHeight*imgWidthStep-2;j+=img->nChannels){
		grayData[(int)j/3]=  (unsigned char) (
			0.299*data[j + 0] +
			0.587*data[j + 1] + 
			0.114*data[j+2] + 0.5);
	}

	
}

//Author: 1041338 - Duy Hòa
//Function: Hàm tính giá trị histogram cho ảnh xám
void MyGrayImage::CalcHist(){

	for(int i=0;i<256;i++){
		this->grayHist[i]=0;
		this->grayHistInt[i]=0;
	}

	int imgHeight=this->grayImg->height;
	int imgWidthStep=this->grayImg->widthStep;
	int step=this->grayImg->widthStep;

	//Tổng số pixel trong ảnh
	int n=this->grayImg->height*this->grayImg->width;

	uchar*data=(uchar*)this->grayImg->imageData;

	//Tính giá trị histogram cho từng giá trị màu [0,1]
	for (int i=0; i < imgHeight; i++) {
		for (int j=0; j < imgWidthStep; j += this->grayImg->nChannels) {
			   this->grayHist[data[j]]+=(float)1/n;		
			   this->grayHistInt[data[j]]+=1;
			}
			data+= step;			
	}

}


//Author: 1041399- Minh Phượng
//Function:Hàm tìm max cho histogram
float MyGrayImage::MaxOfHist(){
	float max=this->grayHist[0];
	for(int i=0;i<256;i++){
		if(this->grayHist[i]>max)
			max=this->grayHist[i];
	}
	return max;
}



//Author: 1041399 - Minh Phượng
//Function:Hàm vẽ histogram cho ảnh xám
IplImage* MyGrayImage::DrawHistogram(float colWidth,float maxHeight){

	//Tạo 1 ảnh rỗng
	IplImage * histImg=cvCreateImage(cvSize(256*colWidth,maxHeight+15),8,1);
	
	//Tính histogram
	CalcHist();

	//Tìm max
	float max=MaxOfHist();
	
	

	//Vẽ nền màu trắng cho histogram
	cvRectangle(histImg,cvPoint(0,0),cvPoint(histImg->width,histImg->height),cvScalar(255,255,255),CV_FILLED,8,0);

	// Vẽ histogram theo hình cột
	for(int i=0,j=0;i<256 && j<(256*colWidth);i++,j+=colWidth){
		
		float n=(this->grayHist[i]*maxHeight)/max;
		cvRectangle(histImg,cvPoint(j,maxHeight),cvPoint(j+colWidth,maxHeight-n),cvScalar(0),1,8,0);

		//Vẽ dãy màu xám tăng dần từ đen đến trắng
		cvRectangle(histImg,cvPoint(j,maxHeight),cvPoint(j+colWidth,maxHeight+15),cvScalar(i),CV_FILLED,8,0);
	}


	return histImg;

}

//Author: 1041399 - Minh Phượng
// Function: Hàm giãn độ tương phản Basic
IplImage * MyGrayImage::StretchContrastBasic(int c, int d)
{
	IplImage *stretchImg=cvCreateImage( cvGetSize(this->grayImg),8,1 );

	//Lấy thông tin của ảnh xám
	int imgHeight=this->grayImg->height;
	int imgWidthStep=this->grayImg->widthStep;
	

	//Lấy dữ liệu của ảnh xám
	uchar *grayData=(uchar*)this->grayImg->imageData;

	//Lấy dữ liệu của ảnh stretch
	uchar *stretchData=(uchar*)stretchImg->imageData;

	
	//Tính histogram
	CalcHist();
	int a=0; //a = min {I(i,j)}
	int b=255; //b = max {I(i,j)}

	//Tìm a
	for(int i=0;i<256;i++){
		if(this->grayHist[i]>0)
		{
			a=i;
			break;
		}
	}

	//Tìm b
	for(int i=255;i>=0;i--){
		if(this->grayHist[i]>0)
		{
			b=i;
			break;
		}
	}
	
	//Tính độ tương phản
	float hs=(float)(d-c)/(b-a);
	for(int j=0;j<imgHeight*imgWidthStep;j+=this->grayImg->nChannels){

		stretchData[j]= c + (grayData[j] - a)*hs;
	}

	return stretchImg;
}

//Author: 1041338 - Duy Hòa
//Function: Hàm giãn độ tương phản cải tiến 1
IplImage *MyGrayImage::StretchContrastAdvance1(int c, int d)
{
	//Tổng số pixel trong ảnh
	int n=this->grayImg->height*this->grayImg->width;

	IplImage *stretchImg=cvCreateImage(cvGetSize(this->grayImg),8,1);

	//Lấy thông tin của ảnh xám
	int imgHeight=this->grayImg->height;
	int imgWidthStep=this->grayImg->widthStep;
	

	//Lấy dữ liệu của ảnh xám
	uchar *grayData=(uchar*)this->grayImg->imageData;

	//Lấy dữ liệu của ảnh stretch
	uchar *stretchData=(uchar*)stretchImg->imageData;

	//Tính histogram
	CalcHist();
	int a=0; //a = 5% giá trị pixels nhỏ hơn a
	int b=255; //b = 5% giá trị pixels lớn hơn b

	int sum1=0,sum2=0;

	//Tìm a
	for(int i=0;i<256-1;i++){
		sum1+=this->grayHistInt[i];
		float pc=(float)(sum1*100)/n;
		if(pc>=0.05)
		{
			a=i+1;
			break;
		}
		
	}

	//Tìm b
	for(int i=255;i>=1;i--){

		//Tính tổng số pixel
		sum2+=this->grayHistInt[i];

		//Tính phần trăm
		float pc=(float)(sum2*100)/n;

		if(pc>=0.05)
		{
			b=i-1;
			break;
		}

	}

	//Tính độ tương phản
	float hs=(float)(d-c)/(b-a);
	for(int j=0;j<imgHeight*imgWidthStep;j+=this->grayImg->nChannels){

		stretchData[j]= c + (grayData[j] - a)*hs;
	}

	return stretchImg;
}


//Author: 1041338 - Duy Hòa , 1041399 - Minh Phượng
//Function: Hàm giãn độ tương phản cải tiến 2
IplImage *MyGrayImage::StretchContrastAdvance2(int c, int d)
{
	//Tổng số pixel trong ảnh
	int n=this->grayImg->height*this->grayImg->width;

	IplImage *stretchImg=cvCreateImage(cvGetSize(this->grayImg),8,1);

	//Lấy thông tin của ảnh xám
	int imgHeight=this->grayImg->height;
	int imgWidthStep=this->grayImg->widthStep;
	

	//Lấy dữ liệu của ảnh xám
	uchar *grayData=(uchar*)this->grayImg->imageData;

	//Lấy dữ liệu của ảnh stretch
	uchar *stretchData=(uchar*)stretchImg->imageData;

	//Tính histogram
	CalcHist();
	int a=0; //a = 5% giá trị pixels nhỏ hơn a
	int b=255; //b = 5% giá trị pixels lớn hơn b


	//Tìm vị trí lớn nhất của Histogram	
	int peak=0;
	for(int i=0;i<256;i++){
		if(this->grayHist[i]>this->grayHist[peak])
			peak=i;
	}
	

	//Tìm a
	for(int i=0;i<256;i++){
		float temp=cutoff*this->grayHist[peak];
		if(this->grayHist[i]>temp)
		{
			a=i;
			break;
		}
		
	}

	//Tìm b
	for(int i=255;i>=1;i--){

		float temp=cutoff*this->grayHist[i];

		if(this->grayHist[i]<temp)
		{
			b=i;
			break;
		}

	}


	//Tính độ tương phản
	float hs=(float)(d-c)/(b-a);
	for(int j=0;j<imgHeight*imgWidthStep;j+=this->grayImg->nChannels){

		stretchData[j]= c + (grayData[j] - a)*hs;
	}


	return stretchImg;
}